
	/**
	 * SHAPE
	 * 
	 * Think of this class as an abstract class
	 * for everything user does with the pen tool.
	 * 
	 * @constructor
	 * @this {Shape}
	 */
	var Shape = function(){};

	/**
	 * @var {String} the namespace of SVG as a string
	 */
	Shape.prototype.ns = "http://www.w3.org/2000/svg";

	/**
	 * @var the element that is being drawn on, SVGLineElement, SVGEllipseElement....
	 */
	Shape.prototype.object;
	
	/** 
	 * @var the element to draw on usually SVGSVGElement 
	 */
	Shape.prototype.canvas;
	
	/** 
	 * @var the element that positions the drawn element; SVGUseElement 
	 */
	Shape.prototype.use;
	
	
	/**
	 * LINE
	 * 
	 * Constructor function for the shape Line
	 * 
	 * @constructor
	 * @this {Line}
	 * @param {SVGSVGElement}
	 */
	var Line = function(el){
		this.canvas = el;
		this.points = [];
		this.x_offset;
		this.y_offset;
	};
	
	Line.prototype.__proto__ = Shape.prototype;
	
	/**
	 * Call before "start drawing".
	 * Create all needed SVG elements, stores the initial mouse/finger position
	 * to be used as offset when we start drawing.
	 * 
	 * @this {Line}
	 * @param {Event} event
	 * @param {Function} callback function
	 */
	Line.prototype.before = function(event){ 
		this.x_offset = event.x;
		this.y_offset = event.y;
		var id = 'polyline' + parseInt(Math.random()*100000);
		this.object = this.canvas.ownerDocument.createElementNS(this.ns,'polyline');
		this.object.setAttribute('id',id);
		this.use = this.canvas.ownerDocument.createElementNS(this.ns,'use');
		this.use.setAttributeNS("http://www.w3.org/1999/xlink", "xlink:href", "#"+id);
		this.use.setAttribute("x",event.x);
		this.use.setAttribute("y",event.y);

		var defs = ( this.canvas.getElementsByTagNameNS(this.ns,'defs').length==0 )
			? this.canvas.ownerDocument.createElementNS(this.ns,'defs') 
			: this.canvas.getElementsByTagNameNS(this.ns,'defs')[0] ;
		
			defs.appendChild(this.object);
		
		this.canvas.appendChild(defs);
		this.canvas.appendChild(this.use);
		this.points.push(event.x-this.x_offset);
		this.points.push(event.y-this.y_offset);
		this.object.setAttribute('points',this.points.join(','));
		
		var callback = arguments[1] || function(){};
			callback.call(this);
	};
	
	/**
	 * Do the actual drawing. Call this function for every mousemove/touchmove
	 * event that is fired and it will draw the line you want. 
	 * 
	 * @param {Event} event
	 * @param {Function} callback function
	 */
	Line.prototype.during = function(event){
		this.points.push(event.x-this.x_offset);
		this.points.push(event.y-this.y_offset);
		this.object.setAttribute('points',this.points.join(','));
		
		var callback = arguments[1] || function(){};
		callback.call(this);
	};
	
	/**
	 * Do some cleanup after the drawing function has stopped
	 * executing.
	 * @param event
	 * @param {Function} callback function
	 */
	Line.prototype.after = function(event){
		this.object = null;
		this.points = [];

		var callback = arguments[1] || function(){};
		callback.call(this);
	};

		
	/**
	 * @SELECT
	 */
	var Select = function(el){
		this.canvas = el;
		this.selection = [];
	};
	Select.prototype.__proto__ = Shape.prototype;
	
	Select.prototype.before = function(event){
		var uselist = this.canvas.getElementsByTagNameNS(this.ns,'use');
		for(var i=0;i<uselist.length;i++){
			var box = uselist[i].getBBox();
			if( (box.x < event.x && (box.x+box.width) > event.x) && (box.y<event.y && (box.y+box.height)>event.y) ){
				this.selection.push(uselist[i]);
			}
		}				
	};
	Select.prototype.during = function(event){
		this.selection.forEach(function(item){
			item.setAttribute('x',event.x);
			item.setAttribute('y',event.y);
		});
	};
	Select.prototype.after = function(event){
		this.selection = [];
	};
		
	
	/**
	 * @APPLICATION
	 * When the mark-up has loaded, but not the images/js/css files
	 * this method can be run. IT will initialize the application, create
	 * the canvas/svg element to draw on, add events to it, create Shape
	 * objects (pen/ellipse...) and everything else needed to run the app.
	 */
	document.addEventListener("DOMContentLoaded",function(event){
		
		//MOUSE DOWN
		//	boolean value that remembers if the user's mouse button
		//	is down
		var mouse_down = false;
		var undo = [];
		var redo = [];
		
		
		//CANVAS
		//	create the drawing element.
		//	this is a SVGSVGElement
		var canvas = document.createElementNS("http://www.w3.org/2000/svg",'svg');
			document.body.appendChild(canvas);
		//SHAPE
		//	default shape to draw
		var pen = new Line(canvas);
		
		/**
		 * MOUSE DOWN
		 */
		canvas.addEventListener('mousedown',function(event){
			mouse_down = true;
			pen.before(event);
		},false);
		
		/**
		 * MOUSE MOVE
		 */
		canvas.addEventListener('mouseup',function(event){
			pen.after(event,function(){
				undo.push({'use':this.use,'object':this.object});
			});
			mouse_down = false;
		},false);
		
		/**
		 * MOUSE UP
		 */
		canvas.addEventListener('mousemove',function(event){
			if(mouse_down){
				pen.during(event);					
			}
		},false);
		
		/**
		 * KEYPRESS - META+Z
		 */
		document.addEventListener('keydown',function(event){
			if(event.metaKey && event.keyCode==90 && !event.shiftKey){
				event.preventDefault();
				var element = undo.pop();
				if(element){
					element['use'].parentNode.removeChild(element['use']);
					element['object'].parentNode.removeChild(element['object']);					
					redo.push(element);
				}
			}
			if(event.metaKey && event.keyCode==90 && event.shiftKey){
				event.preventDefault();
				var element = redo.pop();
				if(element){
					canvas.getElementsByTagName('defs')[0].appendChild(element['object']);
					canvas.appendChild(element['use']);
					undo.push(element);
				}
			}
		},false);

		
		
		var all = {};
		
		
		
		/**
		 * 
		 */
		document.addEventListener('touchstart',function(event){
			event.preventDefault();
			for(var i=0;i<event.touches.length;i++){
				var obj = new Line(canvas);
					obj.before({x:event.touches[i].pageX,y:event.touches[i].pageY});
				all[event.touches[i].identifier] = obj;
			}
		});
		
		document.addEventListener('touchmove',function(event){
			event.preventDefault();
			for(var i=0;i<event.touches.length;i++){
				all[event.touches[i].identifier].during({x:event.touches[i].pageX,y:event.touches[i].pageY});
			}
		});
		
		document.addEventListener('touchend',function(event){
			event.preventDefault();
			for(var i=0;i<event.touches.length;i++){
				all[event.touches[i].identifier].after({x:event.touches[i].pageX,y:event.touches[i].pageY});
			}
		});
		
		
	});